#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project ：NoBad
@File    ：tool_tools.py
@Author  ：LYP
@Date    ：2025/10/31 15:37
@description :
"""
import redis
import base64
import time
from datetime import timedelta
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
from tool.tools import getEnvConfig

# -------------------------- 配置项（需根据项目自定义，建议存环境变量）--------------------------
# AES 密钥：必须 16/24/32 字节（对应 AES-128/AES-192/AES-256），这里用 32 字节示例
AES_SECRET_KEY = b"zhiliao-12345678"  # 实际项目需替换为随机密钥
# Token 过期时长（示例：2 小时）
TOKEN_EXPIRE_HOURS = 2
# AES 初始化向量（IV）长度：固定 16 字节（AES 标准）
AES_IV_LENGTH = 16


class RedisTool(object):
    """
    redis 工具类
    """

    def __init__(self):
        self.host = getEnvConfig("REDIS_HOST", "localhost")
        self.port = int(getEnvConfig("REDIS_PORT", 6379))
        self.password = getEnvConfig("REDIS_PASSWORD", "")
        self.db = int(getEnvConfig("REDIS_DB", 0))
        self.ex = 3600
        max_connections = getEnvConfig("REDIS_MAX_CONNECTIONS", 10)
        try:
            max_connections = int(max_connections)
            if max_connections <= 0:
                raise ValueError("max_connections 必须是正整数")
        except (ValueError, TypeError):
            raise ValueError("max_connections 必须是正整数")

        self.pool = redis.ConnectionPool(host=self.host, port=self.port, password=self.password, db=self.db,
                                         max_connections=max_connections)
        self.client = redis.Redis(connection_pool=self.pool, decode_responses=True)

    def setKey(self, key, values, ex=None):
        """

        :param key:
        :param values:
        :param ex:
        :return:
        """
        if ex is None:
            ex = self.ex
        self.client.set(key, values, ex=ex)
        return True

    def getKey(self, key):
        """

        :param key:
        :return:
        """
        result = self.client.get(key)
        if result:
            return result.decode()
        return None

    def delKey(self, key):
        """

        :param key:
        :return:
        """
        self.client.delete(key)
        return True

    def expireKey(self, key):
        """

        :param key:
        :return:
        """
        self.client.expire(key, self.ex)


_redis = RedisTool()


class CustomTokenTool:

    @staticmethod
    def _aes_encrypt(data: bytes) -> tuple[bytes, bytes]:
        """AES 加密：返回（加密后数据 + 初始化向量 IV）"""
        iv = get_random_bytes(AES_IV_LENGTH)  # 每次加密生成随机 IV（增强安全性）
        cipher = AES.new(AES_SECRET_KEY, AES.MODE_CBC, iv)  # CBC 模式（需 IV 确保同明文不同密文）
        encrypted_data = cipher.encrypt(pad(data, AES.block_size))  # 填充数据至块大小（AES 要求）
        return encrypted_data, iv

    @staticmethod
    def _aes_decrypt(encrypted_data: bytes, iv: bytes) -> bytes:
        """AES 解密：传入加密数据 + IV，返回明文"""
        cipher = AES.new(AES_SECRET_KEY, AES.MODE_CBC, iv)
        decrypted_data = unpad(cipher.decrypt(encrypted_data), AES.block_size)  # 去除填充
        return decrypted_data

    @classmethod
    def generate_token(cls, user_id: int) -> str:
        """
        生成 Token：基于用户 ID + 过期时间戳，AES 加密后 Base64 编码
        :param user_id: 自定义 User 模型的主键 ID（关联用户）
        :return: 最终可传输的 Token 字符串
        """
        # 1. 构建 Token 核心数据（用户 ID + 过期时间戳）
        expire_timestamp = int(time.time()) + int(timedelta(hours=TOKEN_EXPIRE_HOURS).total_seconds())
        token_core = f"{user_id}:{expire_timestamp}".encode("utf-8")  # 格式："用户ID:过期时间戳"
        # 2. AES 加密核心数据
        encrypted_core, iv = cls._aes_encrypt(token_core)
        # 3. 拼接「IV + 加密后数据」，再 Base64 编码（便于 HTTP 传输，避免特殊字符）
        token_bytes = iv + encrypted_core  # IV 需随 Token 一起传输，解密时需用
        token = "Token" + base64.b64encode(token_bytes).decode("utf-8")
        _redis.setKey(token, user_id)
        return token

    @classmethod
    def verify_token(cls, token: str) -> tuple[bool, int or str]:
        """
        校验 Token：解密 + 检查过期 + 提取用户 ID
        :param token: 客户端传入的 Token 字符串
        :return: (是否有效, 有效则返回用户 ID，无效则返回 None)
        """
        try:
            if not token:
                return False, None
            token_key = _redis.getKey(token)
            if token_key:
                return True, token_key
            else:
                return False, None
        except Exception as e:
            # 捕获所有异常（Base64 解码失败、AES 解密失败、格式错误等），均视为 Token 无效
            print(f"Token 校验失败：{str(e)}")
            return False, None

    @classmethod
    def delete_token(cls, token):
        """
        删除 Token（登出时使用）
        :param token: 要删除的 Token 字符串
        """
        if token:
            _redis.delKey(token)


"""
是否生成token，如果token已有且有效则不生成 
"""


def generate_is_user_token(request, user):
    if request:
        existing_token = 0
        if existing_token:
            is_valid, user_id = CustomTokenTool.verify_token(existing_token)
            if is_valid and user_id == user.id:
                return existing_token
    # 生成新的 token
    token = CustomTokenTool.generate_token(user.id)
    if request:
        print(1)
    return token
